package org.iamd.domain.meta;

import java.util.ArrayList;
import java.util.List;

import org.iamd.domain.business.ApplicationException;
import org.iamd.domain.business.BusinessObject;
import org.iamd.domain.data.IData;
import org.iamd.domain.data.IDataAccess;
import org.iamd.util.CommonMsgKeys;
import org.iamd.util.Messenger;
import org.iamd.util.Messenger.ApplicationLocales;

/**
 * Абстрактен клас, осигуряващ функционалност за номенклатурните елементи, които се съдържат в
 * конкретни номенклатури наследници.
 * 
 * @param <D>
 *            VO елемент, от служещ за инстанциране на текущия елемент
 * 
 * @author И. Атанасов
 */
public abstract class AMetaValue<D extends IData> extends
		BusinessObject<D, IDataAccess<D, ? extends Object>> implements Selectable {

	/** Децата на текущия. */
	private List<? extends Selectable> children;

	/** Описание. */
	private String description;

	/** Име за пред потребителя. */
	private String displayName;

	/** Сортиране */
	private Integer ordering;

	/** Родителски елемент. */
	private Selectable parent;

	/** Системно име. */
	private String systemName;

	/**
	 * Конструктор по подразбиране.
	 * 
	 * @throws ApplicationException
	 *             при неуспешно инстанциране
	 */
	public AMetaValue() throws ApplicationException {
		super();
	}

	/**
	 * Конструктор с VO.
	 * 
	 * @param data
	 *            VO номенклатурен елемент
	 * 
	 * @throws ApplicationException
	 *             при неуспешно инстанциране
	 */
	public AMetaValue(D data) throws ApplicationException {
		super(data);
	}

	/**
	 * Конструктор с номенклатурен елемент. Използва се при клониране.
	 * 
	 * @param nomValue
	 *            номенклатурен елемент
	 * 
	 * @throws ApplicationException
	 *             при неуспешно инстанциране
	 */
	protected AMetaValue(AMetaValue<D> nomValue) throws ApplicationException {
		super(nomValue);
	}

	/**
	 * @see Selectable#getChildren()
	 */
	@Override
	public List<? extends Selectable> getChildren() {
		return this.children;
	}

	/**
	 * @return the description
	 */
	@Override
	public String getDescription() {
		return this.description;
	}

	/**
	 * @see Selectable#getDisplayName()
	 */
	@Override
	public String getDisplayName() {
		return this.displayName;
	}

	/**
	 * @see Selectable#getOrdering()
	 */
	@Override
	public Integer getOrdering() {
		return this.ordering;
	}

	/**
	 * @see Selectable#getParent()
	 */
	@Override
	public Selectable getParent() {
		return this.parent;
	}

	/**
	 * @see Selectable#getSystemName()
	 */
	@Override
	public String getSystemName() {
		return this.systemName;
	}

	/**
	 * @see Selectable#isLeaf()
	 */
	@Override
	public boolean isLeaf() {
		return this.children.isEmpty();
	}

	/**
	 * Setter за деца на елемента.
	 * 
	 * @param children
	 *            деца на елемента
	 */
	public void setChildren(List<Selectable> children) {
		this.children = children;
	}

	/**
	 * @see Selectable#setDescription(String)
	 */
	@Override
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * @see Selectable#setDisplayName(String)
	 */
	@Override
	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}

	/**
	 * @see Selectable#setOrdering(Integer)
	 */
	@Override
	public void setOrdering(Integer ordering) {
		this.ordering = ordering;
	}

	/**
	 * @see Selectable#setParent(Selectable)
	 */
	@Override
	public void setParent(Selectable parent) {
		this.parent = parent;
	}

	/**
	 * @see Selectable#setSystemName(String)
	 */
	@Override
	public void setSystemName(String systemName) {
		this.systemName = systemName;
	}

	/**
	 * @return клониран елемент
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected AMetaValue<D> clone() {
		try {
			AMetaValue<D> result = getClass().getDeclaredConstructor(getClass()).newInstance(this);
			List<Selectable> toCopy = new ArrayList<Selectable>();
			for (Selectable nomValue : getChildren()) {
				AMetaValue<D> clone = ((AMetaValue<D>) nomValue).clone();
				clone.setParent(result);
				toCopy.add(clone);
			}
			setChildren(toCopy);
			return result;
		} catch (Exception e) {
			throw new RuntimeException(Messenger.formMessage(
					CommonMsgKeys.M0022_METAVALUE_CLONE_EX, new Object[] { getClass(),
							this.systemName }, ApplicationLocales.SYSTEM_LOCALE), e);
		}
	}

	/**
	 * @see BusinessObject#initialize()
	 */
	@Override
	protected void initialize() throws ApplicationException {
		super.initialize();
		this.systemName = "";
		this.displayName = "";
		this.description = "";
		this.ordering = 0;
		this.children = new ArrayList<Selectable>();
	}

	/**
	 * Елемента е винаги валиден.
	 * 
	 * @see BusinessObject#validate()
	 */
	@Override
	protected void validate() {
		return;
	}

}